# 要改变一个实例的字符串表示，可重新定义它的 __str__() 和 __repr__() 方法。例如：
# class Pair:
#     def __init__(self, x, y):
#         self.x = x
#         self.y = y
#
#     def __repr__(self):
#         return 'Pair({0.x!r}, {0.y!r})'.format(self)
#
#     def __str__(self):
#         return '({0.x!s}, {0.y!s})'.format(self)
#
#
# p = Pair(3, 4)
#
# print('p is {0!r}'.format(p))
# print('p is {0}'.format(p))
# !r 格式化代码指明输出使用 __repr__() 来代替默认的 __str__()

# 为了自定义字符串的格式化，我们需要在类上面定义 __format__() 方法。
# _formats = {
#     'ymd': '{d.year}-{d.month}-{d.day}',
#     'mdy': '{d.month}/{d.day}/{d.year}',
#     'dmy': '{d.day}/{d.month}/{d.year}'
# }
#
#
# class Date:
#     def __init__(self, year, month, day):
#         self.year = year
#         self.month = month
#         self.day = day
#
#     def __format__(self, code):
#         if code == '':
#             code = 'ymd'
#         fmt = _formats[code]
#         return fmt.format(d=self)
#
#
# d = Date(2012, 12, 21)
# print(format(d))
# print(format(d, 'mdy'))
# print('The date is {:ymd}'.format(d))

# 为了让一个对象兼容 with 语句，需要实现 __enter__() 和 __exit__() 方法
# from socket import socket, AF_INET, SOCK_STREAM
#
#
# class LazyConnection:
#     def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
#         self.address = address
#         self.family = family
#         self.type = type
#         self.sock = None
#
#     def __enter__(self):
#         if self.sock is not None:
#             raise RuntimeError('Already connected')
#         self.sock = socket(self.family, self.type)
#         self.sock.connect(self.address)
#         return self.sock
#
#     def __exit__(self, exc_ty, exc_val, tb):
#         self.sock.close()
#         self.sock = None


# 给类添加 __slots__ 属性来极大的减少实例所占的内存，但无法再给实例添加新的属性，只能使用在 __slots__ 中定义的那些属性名
# class Date:
#     __slots__ = ['year', 'month', 'day']
#
#     def __init__(self, year, month, day):
#         self.year = year
#         self.month = month
#         self.day = day


# class Proxy:
#     def __init__(self, obj):
#         self._obj = obj
#
#     # Delegate attribute lookup to internal obj
#     def __getattr__(self, name):
#         return getattr(self._obj, name)
#
#     # Delegate attribute assignment
#     def __setattr__(self, name, value):
#         if name.startswith('_'):
#             super().__setattr__(name, value)  # Call original __setattr__
#         else:
#             setattr(self._obj, name, value)

# __get__() 、__set__() 和 __delete__() 这三个特殊的方法实现三个核心的属性访问操作(get, set, delete)
# class Integer:
#     def __init__(self, name):
#         self.name = name
#
#     def __get__(self, instance, cls):
#         if instance is None:
#             return self
#         else:
#             return instance.__dict__[self.name]
#
#     def __set__(self, instance, value):
#         if not isinstance(value, int):
#             raise TypeError('Expected an int')
#         instance.__dict__[self.name] = value
#
#     def __delete__(self, instance):
#         del instance.__dict__[self.name]


# Base class. Uses a descriptor to set a value
# class Descriptor:
#     def __init__(self, name=None, **opts):
#         self.name = name
#         for key, value in opts.items():
#             setattr(self, key, value)
#
#     def __set__(self, instance, value):
#         instance.__dict__[self.name] = value
#
#
# # Descriptor for enforcing types
# class Typed(Descriptor):
#     expected_type = type(None)
#
#     def __set__(self, instance, value):
#         if not isinstance(value, self.expected_type):
#             raise TypeError('expected ' + str(self.expected_type))
#         super().__set__(instance, value)
#
#
# # Descriptor for enforcing values
# class Unsigned(Descriptor):
#     def __set__(self, instance, value):
#         if value < 0:
#             raise ValueError('Expected >= 0')
#         super().__set__(instance, value)
#
#
# class MaxSized(Descriptor):
#     def __init__(self, name=None, **opts):
#         if 'size' not in opts:
#             raise TypeError('missing size option')
#         super().__init__(name, **opts)
#
#     def __set__(self, instance, value):
#         if len(value) >= self.size:
#             raise ValueError('size must be < ' + str(self.size))
#         super().__set__(instance, value)


# 抽象类
# from abc import ABCMeta, abstractmethod
#
#
# class IStream(metaclass=ABCMeta):
#     @abstractmethod
#     def read(self, maxbytes=-1):
#         pass
#
#     @abstractmethod
#     def write(self, data):
#         pass

#
# class Descriptor:
#     def __init__(self, name=None, **opts):
#         self.name = name
#         for key, value in opts.items():
#             setattr(self, key, value)  # self.key = value
#
#     def __set__(self, instance, value):
#         instance.__dict__[self.name] = value
#
#
# # Descriptor for enforcing types
# class Typed(Descriptor):
#     expected_type = type(None)
#
#     def __set__(self, instance, value):
#         if not isinstance(value, self.expected_type):
#             raise TypeError('expected ' + str(self.expected_type))
#         super().__set__(instance, value)
#
#
# # Descriptor for enforcing values
# class Unsigned(Descriptor):
#     def __set__(self, instance, value):
#         if value < 0:
#             raise ValueError('Expected >= 0')
#         super().__set__(instance, value)
#
#
# class MaxSized(Descriptor):
#     def __init__(self, name=None, **opts):
#         if 'size' not in opts:
#             raise TypeError('missing size option')
#         super().__init__(name, **opts)
#
#     def __set__(self, instance, value):
#         if len(value) >= self.size:
#             raise ValueError('size must be < ' + str(self.size))
#         super().__set__(instance, value)
#
#
# class Integer(Typed):
#     expected_type = int
#
#
# class UnsignedInteger(Integer, Unsigned):
#     pass
#
#
# class Float(Typed):
#     expected_type = float
#
#
# class UnsignedFloat(Float, Unsigned):
#     pass
#
#
# class String(Typed):
#     expected_type = str
#
#
# class SizedString(String, MaxSized):
#     pass
#
#
# class Stock:
#     # Specify constraints
#     name = SizedString('name', size=8)
#     shares = UnsignedInteger('shares')
#     price = UnsignedFloat('price')
#
#     def __init__(self, name, shares, price):
#         self.name = name
#         self.shares = shares
#         self.price = price


# class A: pass
#
#
# class B(A): pass
#
#
# class C(A): pass
#
#
# class D(B, C): pass
#
#
# # print(D.__mro__)  # 查看D类的方法解析顺序
# # 输出: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
#
# class LoggedMappingMixin:
#     """
#     Add logging to get/set/delete operations for debugging.
#     """
#     __slots__ = ()  # 混入类都没有实例变量，因为直接实例化混入类没有任何意义
#
#     def __getitem__(self, key):
#         print('Getting ' + str(key))
#         return super().__getitem__(key)
#
#     def __setitem__(self, key, value):
#         print('Setting {} = {!r}'.format(key, value))
#         return super().__setitem__(key, value)
#
#     def __delitem__(self, key):
#         print('Deleting ' + str(key))
#         return super().__delitem__(key)
#
#
# class SetOnceMappingMixin:
#     '''
#     Only allow a key to be set once.
#     '''
#     __slots__ = ()
#
#     def __setitem__(self, key, value):
#         if key in self:
#             raise KeyError(str(key) + ' already set')
#         return super().__setitem__(key, value)
#
#
# class StringKeysMappingMixin:
#     '''
#     Restrict keys to strings only
#     '''
#     __slots__ = ()
#
#     def __setitem__(self, key, value):
#         if not isinstance(key, str):
#             raise TypeError('keys must be strings')
#         return super().__setitem__(key, value)
#
#
# class LoggedDict(LoggedMappingMixin, dict):
#     pass
#
#
# d = LoggedDict()
# print(LoggedDict.__mro__)  # 查看D类的方法解析顺序
# d['x'] = 23
# print(d['x'])
# del d['x']
#
#
# class LoggingMixin:
#     def log(self, message):
#         print(f"Log: {message}")
#
#
# class Calculator(LoggingMixin):  # Calculator具有日志功能，但不是Logging的子类
#     def add(self, a, b):
#         result = a + b
#         self.log(f"Adding {a} + {b} = {result}")
#         return result


# class Connection:
#     """新方案——对每个状态定义一个类"""
#
#     def __init__(self):
#         self.new_state(ClosedConnectionState)
#
#     def new_state(self, newstate):
#         self._state = newstate
#         # Delegate to the state class
#
#     def read(self):
#         return self._state.read(self)
#
#     def write(self, data):
#         return self._state.write(self, data)
#
#     def open(self):
#         return self._state.open(self)
#
#     def close(self):
#         return self._state.close(self)
#
#
# # Connection state base class
# class ConnectionState:
#     @staticmethod
#     def read(conn):
#         raise NotImplementedError()
#
#     @staticmethod
#     def write(conn, data):
#         raise NotImplementedError()
#
#     @staticmethod
#     def open(conn):
#         raise NotImplementedError()
#
#     @staticmethod
#     def close(conn):
#         raise NotImplementedError()
#
#
# # Implementation of different states
# class ClosedConnectionState(ConnectionState):
#     @staticmethod
#     def read(conn):
#         raise RuntimeError('Not open')
#
#     @staticmethod
#     def write(conn, data):
#         raise RuntimeError('Not open')
#
#     @staticmethod
#     def open(conn):
#         conn.new_state(OpenConnectionState)
#
#     @staticmethod
#     def close(conn):
#         raise RuntimeError('Already closed')
#
#
# class OpenConnectionState(ConnectionState):
#     @staticmethod
#     def read(conn):
#         print('reading')
#
#     @staticmethod
#     def write(conn, data):
#         print('writing')
#
#     @staticmethod
#     def open(conn):
#         raise RuntimeError('Already open')
#
#     @staticmethod
#     def close(conn):
#         conn.new_state(ClosedConnectionState)
